/*
 * Copyright (C) 2011 JiangHongTiao <jjurco.sk_gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package sk.lieskove.jianghongtiao.websearch;

import org.apache.log4j.Logger;
import sk.lieskove.jianghongtiao.common.enums.searchserviceenum.SearchServiceEnum;
import sk.lieskove.jianghongtiao.common.exceptions.InvalidPropertiesSettingsException;
import sk.lieskove.jianghongtiao.common.utils.PropertiesUtils;
import sk.lieskove.jianghongtiao.commonpersist.Persist;
import sk.lieskove.jianghongtiao.websearch.document.preprocessing.ThreadPreprocessorManager;
import sk.lieskove.jianghongtiao.websearch.service.ExcludeReasonEnum;
import sk.lieskove.jianghongtiao.websearch.service.SearchQuery;
import sk.lieskove.jianghongtiao.websearch.persistence.WebSearchResponse;
import sk.lieskove.jianghongtiao.websearch.service.ares.AresSearch;
import sk.lieskove.jianghongtiao.websearch.service.searchengine.GYBWebSearch;

import java.util.*;

/**
 * Date of create: Oct 12, 2011
 *
 * @author JiangHongTiao <jjurco.sk_gmail.com>
 * @version 2011.1012
 */
public class FullWebSearch implements WebSearch {

    private Logger log = Logger.getLogger(FullWebSearch.class);
    private PropertiesUtils pu = new PropertiesUtils(FullWebSearch.class);

    @Override
    public List<WebSearchResponse> search(SearchQuery query, int numberOfResults,
            SearchServiceEnum... services) {
        List<WebSearchResponse> searchResults = new ArrayList<WebSearchResponse>();
        List<WebSearchResponse> results = new ArrayList<WebSearchResponse>();
        try {
            if (!Collections.disjoint(Arrays.asList(services),
                    Arrays.asList(AresSearch.SUPPORTED_SERVICES))) {
                AresSearch as = new AresSearch();
                searchResults.addAll(as.search(query, numberOfResults, services));
            }
            if (!Collections.disjoint(Arrays.asList(services),
                    Arrays.asList(GYBWebSearch.SUPPORTED_SERVICES))) {
                GYBWebSearch ws = new GYBWebSearch();
                searchResults.addAll(ws.search(query, numberOfResults, services));
            }
        } catch (InvalidPropertiesSettingsException ex) {
            log.error("Required settings for the search service was not found!", ex);
        }
        
        Map<WebSearchResponse, ThreadPreprocessorManager> tpmMap = 
                new HashMap<WebSearchResponse, ThreadPreprocessorManager>();
        Set<String> foundUrls = new HashSet<String>();
        for (WebSearchResponse wsr : searchResults) {
            if(!foundUrls.contains(wsr.getUrl())){
                foundUrls.add(wsr.getUrl());
            } else {
                wsr.setExcludeReasonEnum(ExcludeReasonEnum.URL_ALREADY_FOUND);
            }
            if (wsr.isAdequateDocument()) {
                ThreadPreprocessorManager tpm = new ThreadPreprocessorManager(wsr, 
                        "PreprocessThread: "+wsr.getOriginalFileLocation());
                tpmMap.put(wsr, tpm);
                tpm.start();
            }
        }

        Persist p = Persist.getSingleton();
        for (WebSearchResponse wsr : searchResults) {
            //not everything will be processed, thread can change it
            if (wsr.isAdequateDocument()) {
                ThreadPreprocessorManager tpm = tpmMap.get(wsr);
                try {
                    //wait for thread end
                    tpm.join();
                } catch (InterruptedException ex) {
                    log.warn("Thread was interrupted: "+tpm.getName());
                }
                //if still is adequate, add it to results
                //it can change later, we have to check it also when thread finishes
                if (wsr.isAdequateDocument()) {
                    results.add(wsr);
                }
            }
            p.searchResults(wsr);
        }

        return results;
    }

    @Override
    public List<WebSearchResponse> search(SearchQuery query,
            SearchServiceEnum... services) {
        String max = pu.getProperty("maximal-number-of-results");
        int numberOfResults = 50;
        if (max != null) {
            numberOfResults = Integer.parseInt(max);
        }
        return search(query, numberOfResults, services);
    }

    @Override
    public List<WebSearchResponse> searchAll(SearchQuery query,
            int numberOfResults) {
        return search(query, numberOfResults, SearchServiceEnum.values());
    }

    @Override
    public List<WebSearchResponse> searchAll(SearchQuery query) {
        return search(query, SearchServiceEnum.values());
    }
}
